package com.cartoonrabbit.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cartoonrabbit.config.minio.MinioProperties;
import com.cartoonrabbit.config.minio.MinioUtils;
import com.cartoonrabbit.pojo.InviteRecord;
import com.cartoonrabbit.pojo.User;
import com.cartoonrabbit.service.IImageHandleService;
import com.cartoonrabbit.service.IInviteRecordService;
import com.cartoonrabbit.service.IUserService;
import com.cartoonrabbit.vo.RespBean;
import com.cartoonrabbit.wxapp.utils.ImageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * https://www.vvso.cn/xlbk/20230.html
 */
@Service
public class ImageHandleServiceImpl implements IImageHandleService {
    public static String userDir = System.getProperty("user.dir");
    // 卡通训练模型文件路径数组
    public static String[] checkpoints = {
            userDir + "/animegan2/weights/qingxin.pt",
            userDir + "/animegan2/weights/weimei.pt",
            userDir + "/animegan2/weights/gufeng.pt",
            userDir + "/animegan2/weights/guichu.pt"
    };

    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private MinioProperties minioProperties;

    @Autowired
    private IUserService userService;

    @Autowired
    private IInviteRecordService inviteRecordService;

    /**
     * 图片转卡通
     *
     * @param imageFile
     * @param type
     * @param openId
     * @return
     */
    @Override
    @Transactional
    public RespBean tranforCartoon(MultipartFile imageFile, Integer type, String openId) {
        //创建java缓存图片目录
        File tempDir = new File(userDir + "/temp");
        if (!tempDir.exists() && !tempDir.isDirectory()) {
            tempDir.mkdirs();
        }
        File outDir = new File(userDir + "/outDir");
        if (!outDir.exists() && !outDir.isDirectory()) {
            outDir.mkdirs();
        }
        try {
            User user = userService.getById(openId);
            if (user.getProductTimes()<=0){
                return RespBean.fail("制作次数不足，请充值");
            }
            // 对图片进行压缩
            MultipartFile compressImageMultiPartFile = ImageUtils.compressImage(imageFile);
            // 图片压缩之后进行保存
            String savePath = tempDir.getCanonicalPath() + "/" + compressImageMultiPartFile.getOriginalFilename();
            compressImageMultiPartFile.transferTo(Paths.get(savePath));
            File saveImageFile = new File(savePath);
            // 对压缩后的图片进行卡通处理
            JSONObject jsonObject = doCartoon(tempDir.getPath(), outDir.getPath(), compressImageMultiPartFile.getOriginalFilename(), type);
            if (jsonObject.getInt("code") != 200) {
                saveImageFile.delete();
                return RespBean.fail(jsonObject.getStr("message"));
            } else {
                // 获取到对应的卡通图片路径
                String cartoonImagePath = jsonObject.getStr("data");
                File cartoonImageFile = new File(cartoonImagePath);
                if (!cartoonImageFile.exists()) {
                    saveImageFile.delete();
                    return RespBean.fail("图片保存异常");
                } else {
                    // 对图片上传到minio
                    FileInputStream fileInputStream = new FileInputStream(cartoonImageFile);
                    CommonsMultipartFile multipartFile = ImageUtils.createMultipartFile(fileInputStream, cartoonImageFile.getName());
//                    MultipartFile compressCartoonImage = ImageUtils.compressImage(multipartFile);
                    List<String> netUrls = minioUtils.upload(new MultipartFile[]{multipartFile}, minioProperties.getBucketName());
                    cartoonImageFile.delete();
                    saveImageFile.delete();
                    String imageUrl = minioProperties.getEndpoint() + "/" + netUrls.get(0);
                    Map<String,Object> response=new HashMap<>();
                    response.put("img_url",imageUrl);
                    // todo 用户制作次数减一

                    user.setProductTimes(user.getProductTimes()-1);
                    userService.updateById(user);
//                    response.put("userInfo",user);
                    // 对邀请记录进行操作
                    InviteRecord inviteRecord = inviteRecordService.getOne(new QueryWrapper<InviteRecord>().eq("invited_openId", openId));
                    if (!ObjectUtils.isEmpty(inviteRecord)){
                        inviteRecord.setUserTimes(inviteRecord.getUserTimes()+1);
                        // 判断是否要加红包
                        if (inviteRecord.getUserTimes()%10==0){// 需要给对应的用户加提成
                            // 获取随机金额
                            int randomMoney = RandomUtil.randomInt(1, 11);
                            inviteRecord.setAwardMoney(inviteRecord.getAwardMoney()+randomMoney);
                            User inviteUser = userService.getById(inviteRecord.getInviteId());
                            inviteUser.setBalance(inviteUser.getBalance()+randomMoney);
                            userService.updateById(inviteUser);
                        }
                    }
                    return RespBean.success("SUCCESS", response);
                }
            }
        } catch (Exception e) {
            return RespBean.fail("服务器异常");
        }
    }

    /**
     * @param inpuDir   输入目录
     * @param outDir    输出目录
     * @param imageName 图片名称
     * @param type      需要转化的卡通类型
     * @return
     */
    private JSONObject doCartoon(String inpuDir, String outDir, String imageName, Integer type) {
        JSONObject jsonObject = new JSONObject();
            try {
                String result = "";
                String[] cmd = {"/root/anaconda2/envs/pytorch/bin/python",
                        userDir + "/animegan2/application.py",
                        "--input_dir", inpuDir,
                        "--output_dir", outDir,
                        "--image_name", imageName,
                        "--checkpoint", checkpoints[type - 1]};
                Process pr = Runtime.getRuntime().exec(cmd);

                Thread thread=new Thread(new Runnable() {
                    @Override
                    public void run() {
                        int time=0;
                        while (time<=240){
                            time++;
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        try {
                            pr.exitValue();
                        }catch (Exception e){
                            pr.destroy();
                        }
                    }
                });
                thread.start();
                BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream(), "GBK"));
                result = input.readLine();
                while ((input.readLine()) != null) {
                }
                //获取进程的标准输入流
                final InputStream is1 = pr.getInputStream();
                //获取进城的错误流
                final InputStream is2 = pr.getErrorStream();
                //启动两个线程，一个线程负责读标准输出流，另一个负责读标准错误流
                new Thread() {
                    public void run() {
                        BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
                        try {
                            String line1 = null;
                            while ((line1 = br1.readLine()) != null) {
                                if (line1 != null){}
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        finally{
                            try {
                                is1.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start();

                new Thread() {
                    public void  run() {
                        BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));
                        try {
                            String line2 = null ;
                            while ((line2 = br2.readLine()) !=  null ) {
                                if (line2 != null){}
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        finally{
                            try {
                                is2.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start();
                int exitCode = pr.waitFor();// 等待程序执行
                input.close();
                if (exitCode == 0) {// 操作成功
                    JSONObject pythonRes = JSONUtil.parseObj(result);
                    Integer code = pythonRes.getInt("code");
                    if (code == 200) {// 操作成功
                        jsonObject.putOnce("code", pythonRes.get("code"));
                        jsonObject.putOnce("message", pythonRes.get("message"));
                        jsonObject.putOnce("data", pythonRes.get("data"));
                    } else {
                        jsonObject.putOnce("code", pythonRes.get("code"));
                        jsonObject.putOnce("message", pythonRes.get("message"));
                    }
                } else {// 操作失败
                    BufferedReader errorResultReader = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
                    String errorLine;
                    while ((errorLine = errorResultReader.readLine()) != null) {
                        System.out.println(errorLine);
                    }
                    jsonObject.putOnce("code", 500);
                    jsonObject.putOnce("message", "图片处理程序异常");
                }
            } catch (Exception e) {
                jsonObject.putOnce("code", 500);
                jsonObject.putOnce("message", "服务器异常");
            }
        return jsonObject;
    }
}
